#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

import os
from typing import Union

from common.parse_parafile import get_env_variable
from common.schemas.thrift_base_data_type import Application, RepositoryDataType, BackupJobType
from common.schemas.thrift_plugin import BackupJob, RestoreJob
from saporacle.comm.logger import logger
from saporacle.backup.data_backup_saporacle import DataBackupSAPOracle
from saporacle.backup.log_backup_saporacle import LogBackupSAPOracle
from saporacle.comm.repository import Repository
from saporacle.restore.restore_saporacle import RestoreSAPOracle
from saporacle.resource.saporacle import SAPOracle
from saporacle.backup.saporacle_data_backup_service import SAPOracleDataBackupService
from saporacle.backup.saporacle_log_backup_service import SAPOracleLogBackupService
from saporacle.resource.saporacle_resource_service import SAPOracleResourceService
from saporacle.restore.saporacle_restore_service import SAPOracleRestoreService


class Factory:

    def __init__(self, pid: str) -> None:
        self._pid = pid

    """创建 domain"""

    @staticmethod
    def create_repository(model: Union[BackupJob, RestoreJob]) -> Repository:
        if isinstance(model, BackupJob) and model.job_param.backup_type == BackupJobType.FULL_BACKUP:
            # UBC 框架问题 数据备份路径需要插件侧再拼接
            data_paths = [os.path.join(p, model.copies[0].id)
                          for repo in model.repositories for p in repo.path or []
                          if repo.repository_type == RepositoryDataType.DATA_REPOSITORY]
            cache_paths = sum((repo.path or [] for repo in model.repositories
                               if repo.repository_type == RepositoryDataType.CACHE_REPOSITORY), [])
        elif isinstance(model, BackupJob) and model.job_param.backup_type == BackupJobType.LOG_BAKCUP:
            data_paths = sum((repo.path or [] for repo in model.repositories
                              if repo.repository_type == RepositoryDataType.LOG_REPOSITORY), [])
            cache_paths = sum((repo.path or [] for repo in model.repositories
                               if repo.repository_type == RepositoryDataType.CACHE_REPOSITORY), [])
        elif isinstance(model, RestoreJob):
            types = [RepositoryDataType.DATA_REPOSITORY, RepositoryDataType.LOG_REPOSITORY]
            data_paths = sum((repo.path or [] for _copy in model.copies for repo in _copy.repositories
                              if repo.repository_type in types), [])
            # 日志恢复任务，框架只下发两个时间大小顺序排列的副本，全量+日志。日志副本中 repositories 是历次日志副本,也按时间大小顺序排列
            data_paths.reverse()
            cache_paths = sum((repo.path or [] for _copy in model.copies for repo in _copy.repositories
                               if repo.repository_type == RepositoryDataType.CACHE_REPOSITORY), [])
        return Repository(data_paths, cache_paths)

    def create_saporacle(self, model: Union[Application, BackupJob, RestoreJob]) \
            -> Union[None, SAPOracle, DataBackupSAPOracle, LogBackupSAPOracle, RestoreSAPOracle]:
        key = (get_env_variable(f"application_auth_authKey_{self._pid}")
               or get_env_variable(f"job_protectObject_auth_authKey_{self._pid}")
               or get_env_variable(f"job_targetObject_auth_authKey_{self._pid}"))
        pwd = (get_env_variable(f"application_auth_authPwd_{self._pid}")
               or get_env_variable(f"job_protectObject_auth_authPwd_{self._pid}")
               or get_env_variable(f"job_targetObject_auth_authPwd_{self._pid}"))
        if not key or not pwd:
            logger.error("Cannot get login authentication.")
            return None
        if isinstance(model, Application):
            extend_info = model.extend_info
            # 待解决： 下发的 oraclesid 字段
            return SAPOracle(extend_info["oraclesid"], extend_info["sapsid"], extend_info["oraclesid"],
                             extend_info["sapsid"], key, pwd)
        elif isinstance(model, BackupJob) and model.job_param.backup_type == BackupJobType.FULL_BACKUP:
            extend_info = model.protect_object.extend_info
            return DataBackupSAPOracle(extend_info["oraclesid"], extend_info["sapsid"], key, pwd)
        elif isinstance(model, BackupJob) and model.job_param.backup_type == BackupJobType.LOG_BAKCUP:
            extend_info = model.protect_object.extend_info
            return LogBackupSAPOracle(extend_info["oraclesid"], extend_info["sapsid"], key, pwd)
        elif isinstance(model, RestoreJob):
            extend_info = model.target_object.extend_info
            source_extend_info = model.copies[0].protect_object.extend_info
            return RestoreSAPOracle(extend_info["oraclesid"], extend_info["sapsid"], source_extend_info["oraclesid"],
                                    source_extend_info["sapsid"], key, pwd)

    """创建 service"""

    def create_resource_service(self, application: Application) -> SAPOracleResourceService:
        saporacle = self.create_saporacle(application)
        resource_service = SAPOracleResourceService(self._pid, saporacle)
        return resource_service

    def create_backup_service(self, backup_job: BackupJob) \
            -> Union[SAPOracleDataBackupService, SAPOracleLogBackupService]:
        saporacle = self.create_saporacle(backup_job)
        repository = self.create_repository(backup_job)
        if backup_job.job_param.backup_type == BackupJobType.FULL_BACKUP:
            backup_service = SAPOracleDataBackupService(self._pid, saporacle, repository)
        elif backup_job.job_param.backup_type == BackupJobType.LOG_BAKCUP:
            backup_service = SAPOracleLogBackupService(self._pid, saporacle, repository)
        return backup_service

    def create_restore_service(self, restore_job: RestoreJob) -> SAPOracleRestoreService:
        saporacle = self.create_saporacle(restore_job)
        repository = self.create_repository(restore_job)
        restore_service = SAPOracleRestoreService(self._pid, saporacle, repository)
        return restore_service

